The present invention relates to the field of computer program security, and more particularly a method and device for detecting unacceptable steps in the execution of a computer program, the latter being able to be in a low-level or high-level language.
In a program in low-level language, the commands are formulated according to a structure very close to that of the instructions actually executed by the processor part of the computer. The program requires only to be compiled before being able to be executed. Low-level languages, known by the name of machine code, are used notably for programming microprocessors or microcontrollers. Microcontrollers are processors which can execute only a small number of specific instructions. They are used notably for equipping smart cards (bank cards, telephone cards, cards providing access to services, etc) and for controlling industrial or domestic equipment.
In a program in high-level language, the commands have a structure closer to natural language, but on the other hand further away from that used by the processor. The commands written in such languages must first of all be interpreted, that is to say converted into machine code commands, before then being able to be put in the form of instructions with a view to their execution by the processor.
Thus any computer program gives rise to a series of instructions adapted to the processor, microprocessor or microcontroller for which it is intended.
Conventionally, the instructions of a program are executed by a processor in a sequence governed by an instruction counter, as will be described briefly with reference to FIG. 1.
The compiled instructions of a program are loaded in blocks of successive instructions Inst.1, Inst.2, Inst.3, . . . , Inst.n (where n is an integer) in the form of codes or microcodes in an instruction register 2. Each instruction is identified by a specific address in this register 2. In the example, the addresses of the instructions Inst.1, Inst.2, Inst.3, . . . , Inst.n are designated respectively Ad.1, Ad.2, Ad.3, . . . , Ad.n. The instructions are read from the instruction register 2 and loaded successively into the processor 4 in order to be executed therein under the control of an instruction counter 6, itself controlled by the processor 4. For this purpose, the instruction counter 6 has an address pointer 8 which designates the address Ad.1, . . . Ad.n of the register 2 from which the instruction to be loaded into the processor 4 during the execution of an instruction sequence must be read. The position of the pointer 8 vis-à-vis addresses in the instruction register 2 therefore changes along with the execution of the instructions.
In the example depicted in FIG. 1, the instructions Inst.1, Inst.2, Inst.3, . . . , Inst.n in the register 2 must be executed successively from the first instruction Inst.1 to the nth instruction Inst.n, that is to say in a linear fashion. Thus the pointer 8 of the instruction counter 6 designates initially the address Ad.1 of the register 2, and the data 10-1 of the corresponding instruction Inst.1 are loaded into the processor 4. When the processor 4 orders the instruction counter 6 to supply the next instruction (in this case Inst.2), the said counter increments the position of the pointer 8 by one address change unit in order to designate the address Ad.2. This process is repeated and terminates when the pointer 8 designates the address Ad.n in order to load the data 10-n of the last instruction Inst.n (dotted lines).
A series of instructions executed in a linear fashion does not contain any “jumps” which escape from the sequential progression of the pointer 8 vis-à-vis successive addresses. This is the case, for example, with a sequence of instructions in microcodes such as:
ldattxamulbset3,tstan
In other words, this sequence will be executed in a linear fashion, the instruction counter 6 being incremented by one address change unit when passing from one instruction to another.
However, it is normal for the execution of a program to require jumps to instructions outside the linear sequence of the instructions as presented in the register 2. Such jumps can result from an instruction for loading data situated in an address outside the sequence, or from an instruction, referred to as a switching instruction, for conditional execution of the following command.
An instruction which causes a jump makes it necessary, at the instruction counter 6, to determine the address in the register 2 of the next instruction following this jump and to position the pointer 8 at this address so that the instruction or the data situated there is loaded into the processor 2.
By way of example, the sequence:
ldatxabralabel;jumpmulbset3,tstanlabelrts
will cause the loading of a new value into the instruction counter 6 at the position in the code corresponding to the comment “jump”.
The fact of thus being able to make, under command, jumps to addresses outside a sequential series of addresses may unfortunately give rise to unacceptable steps in the program. Such unacceptable steps in the program may result from an accidental malfunctioning of the program device. However, it may also result from a malevolent action aimed at diverting the functioning of the program device from its required function. For example, in the case of a smart card, modifications to the programming of the microprocessor by creating or modifying jumps and/or switches may make it possible to load erroneous data (increasing credit authorised with a bank or telephone card, false authorisation of access to certain services, etc) or to recover confidential data stored in memory (access code, personal information concerning the holder of the card, etc).
This is because, even when the programs are recorded in a fixed manner on a semiconductor chip, it is possible, with current techniques for probing and testing components, to create probing contacts on the surface of the chip (or even in the low layers thereof) using work stations with focus ion beams or FIBs.
Once created, these probing points make it possible to deposit probing spikes using specialised workbenches, also known by the English term “probe stations”, allowing the continuous reading of a bit (and the monitoring of its change over time) or an external modification of its value.
In particular, depositing contacts on the register of the instruction counter 6 makes it possible to externally load the value of the register currently being executed and to cause a switching not provided for by the program designer. As explained above, such a jump may naturally have harmful consequences for the security of the application and, for example, result in the disclosure of secret data whilst effecting incomplete calculations.
There also exist more rudimentary, but less certain, ways of causing such malfunctioning in the running of the program. One example is given in an article entitled “Tamper resistance, a cautionary note” by R. Anderson. Another technique consists of exploiting calculation errors deliberately caused in order to extract, from a smart card, data such as the secret keys. This technique is described in the article entitled “On the Importance of Checking Computations” by Boneh, DeMillo and Lipton; Bellcore Report, published on 31 Oct. 1996.
Naturally, the same phenomenon can also occur when the program attacked is interpreted instead of being compiled. Thus an application in Java or Basic language can be diverted from its legitimate use if the attacker manages, for example, to cause a change in the program pointer of the interpreter indicating the current instruction to the interpreter.
However, current computer systems are not specifically designed to prevent uncontrolled switchings within a code. Quite the contrary, the assembly languages have been specifically designed to allow the maximum freedom to the programmer. By way of example, in C language, it is possible to jump within the code of a function using the execution indexed by the pointer.